package cc.linker.steplink.crm.web.cas;

import cc.linker.steplink.crm.commons.utils.MD5;
import lombok.AllArgsConstructor;
import org.jasig.cas.client.session.SessionMappingStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;

import javax.servlet.http.HttpSession;
import java.util.concurrent.TimeUnit;

/**
 * .实现session存储
 * <p>
 * 默认实现为内存存储，本实现为redis存储
 * session共享已集成spring的实现，关键在单点注销
 * 由于牵涉到三端交互，肯定需要额外的存储器存储ST票据和session的关系，这个
 * HashMapBackedSessionMappingStorage已做了实现
 * {@link org.jasig.cas.client.session.HashMapBackedSessionMappingStorage}
 * 但不适合集群环境，需考虑session序列化，目前未予解决。
 * <p>
 * 利用RedisOperationsSessionRepository已实现的功能，调用其<code>delete(String sessionId)</code>删除
 *
 * @author zhaomengwei
 */
@AllArgsConstructor
public final class RedisSessionMappingStorage implements SessionMappingStorage {
    private static final String CAS_TICKET_PREFIX = "SLO:ST:";
    private static final String SESSION_ID_PREFIX = "SLO:SID:";
    private static final Integer SESSION_TIMEOUT = 1800;

    private RedisTemplate redisTemplate;

    private RedisOperationsSessionRepository sessionRepository;

    private final Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 维护sessionId和cas的ST票据的关联关系
     *
     * @param mappingId
     * @param session
     */
    @Override
    public synchronized void addSessionById(String mappingId, HttpSession session) {
        redisTemplate.boundValueOps(SESSION_ID_PREFIX + session.getId()).set(mappingId);
        redisTemplate.boundValueOps(SESSION_ID_PREFIX + session.getId()).expire(SESSION_TIMEOUT, TimeUnit.SECONDS);
        redisTemplate.boundValueOps(CAS_TICKET_PREFIX + mappingId).set(session.getId());
        redisTemplate.boundValueOps(CAS_TICKET_PREFIX + mappingId).expire(SESSION_TIMEOUT, TimeUnit.SECONDS);
    }

    @Override
    public synchronized void removeBySessionById(final String sessionId) {
        logger.info("Attempting to remove Session=[{}]", sessionId);

        final String key = (String) redisTemplate.boundValueOps(SESSION_ID_PREFIX + sessionId).get();

        if (logger.isDebugEnabled()) {
            if (key != null) {
                logger.debug("Found mapping for session.  Session Removed.");
            } else {
                logger.debug("No mapping for session found.  Ignoring.");
            }
        }
        redisTemplate.delete(CAS_TICKET_PREFIX + key);
        redisTemplate.delete(SESSION_ID_PREFIX + sessionId);

        String ht = MD5.encode(sessionId);
        redisTemplate.delete("pc_login:" + ht);
    }

    /**
     * 不返回HttpSession实例，直接在此彻底解决
     *
     * @param mappingId
     * @return
     */
    @Override
    public synchronized HttpSession removeSessionByMappingId(String mappingId) {
        String sessionId = (String) redisTemplate.boundValueOps(CAS_TICKET_PREFIX + mappingId).get();
//        sessionRepository.delete(sessionId);
        sessionRepository.deleteById(sessionId);
        return null;
    }
}

